class Car {
    public engine: string;
    public version:string;
    constructor(engine?: string, version?: string) {
        this.engine = engine ?? 'V8';
        this.version = version ?? '1.0';
    }
    public getter(key: 'engine' | 'version') {
        if( key === 'engine' ) {
            return this.engine;
        }
        if( key === 'version' ) {
            return this.version;
        }
        throw new Error('Invalid key');
    }
    public setter(key: 'engine' | 'version', value: string):boolean {
        if (key === 'engine') {
            this.engine = value;
            return true;
        } else if (key === 'version') {
            this.version = value;
            return true;
        }
        throw new Error('Invalid key');
    }
}

let car = new Car();
car.engine = 'V10';
car.version = '1.2';
console.log(car.getter('engine'));
car.setter('version', '1.1')
console.log(car.version);



/**
 * 继承类的方法重写
 * 类继承后，子类可以对父类的方法重新定义，这个过程称之为方法的重写。
 *
 * 其中 super 关键字是对父类的直接引用，该关键字可以引用父类的属性和方法。
 */
class Shape {
    public Area: number | undefined;
    constructor() {

    }
    display() {
        console.log("Area is " + this.Area);
    }
}
class Circle extends  Shape {
    r : number;
    constructor(r: number) {
        super();
        this.r = r;
        this.Area = Math.PI * r * r;
    }
    display() {
        console.log("圆的半径为" + this.r +", 则面积：" + this.Area?.toFixed(2));
    }
}
class Rectangle extends Shape {
    l : number;
    h : number;
    constructor(l: number, h: number) {
        super();
        this.l = l;
        this.h = h;
        this.Area = l * h;
    }
    display() {
        console.log("矩形的长为" + this.l +", 宽为" + this.h +"，则面积：" + this.Area?.toFixed(2));
    }
}
class Triangle extends Shape {
    b : number;
    h : number;
    constructor(b: number, h: number) {
        super();
        this.b = b;
        this.h = h;
        this.Area = (b * h) / 2;
    }
    display() {
        console.log("三角形的底为" + this.b +", 高为" + this.h +"，则面积：" + this.Area?.toFixed(2));
    }
}

/**
 * 需要注意的是子类只能继承一个父类，TypeScript 不支持继承多个类，但支持多重继承
 */
class Square extends Rectangle {
    a: number;
    constructor(a: number) {
        super(a, a);
        this.a = a;
        this.Area = a * a;
    }
    display() {
        // super.display();  // 调用父类的方法
        console.log("正方形的边为" + this.a + ", 则面积：" + this.Area?.toFixed(2));
    }
}

let circle = new Circle(5);
circle.display();

let rectangle = new Rectangle(5, 10);
rectangle.display();

let triangle = new Triangle(5, 10);
triangle.display();

let square = new Square(5);
square.display();


/**
 * static 关键字
 * static 关键字用于定义类的数据成员（属性和方法）为静态的，静态成员可以直接通过类名调用。
 */
class Animal {
    static AnimalName: string;
    static move() {
        console.log("Animal move " + Animal.AnimalName);
    }
}
Animal.AnimalName = 'Cat';
Animal.move();

class Person {}
class Student extends Person {}
let student = new Student();
let isPerson = student instanceof Person;
console.log(isPerson);


/**
 * 接口
 * 接口（Interfaces）可以用于对类的一部分行为进行抽象，或者对类的形状进行定义。
 * 接口使用关键字 interface 定义，接口可以定义一个方法或者一个属性，接口也可以继承其他接口。
 * 接口可以定义一个类，只要实现了接口中的方法或者属性，那么这个类就是实现了这个接口。
 */
interface IAnimal {
    AnimalName: string;
    move(): void;
}
interface IAnimal2 {
    eat(): void;
}

/**
 * 类可以实现接口，使用关键字 implements
 */
class Dog implements IAnimal, IAnimal2 {
    AnimalName: string;
    constructor(AnimalName : string) {
        this.AnimalName = AnimalName;
    }
    move() {
        console.log(this.AnimalName + " is moving...");
    }
    eat() {
        console.log(this.AnimalName + " is eating...");
    }
}

let dog = new Dog("旺财");
dog.move();
dog.eat();